Modification start date
[BattleCats.git] / Assets / Scripts / Imported / Tilemap / Brushes / GameObject Brush / Scripts / Editor / GameObjectBrush.cs
blobb13a9309cf0812fa16ef624143603cc283f16fc8
1 using System;
2 using System.Linq;
3 using UnityEngine;
4 using UnityEngine.Tilemaps;
5 using Object = UnityEngine.Object;
7 namespace UnityEditor
9 [CustomGridBrush(true, false, false, "GameObject Brush")]
10 public class GameObjectBrush : GridBrushBase
12 [SerializeField]
13 [HideInInspector]
14 private BrushCell[] m_Cells;
16 [SerializeField]
17 [HideInInspector]
18 private Vector3Int m_Size;
20 [SerializeField]
21 [HideInInspector]
22 private Vector3Int m_Pivot;
24 public Vector3Int size { get { return m_Size; } set { m_Size = value; SizeUpdated(); } }
25 public Vector3Int pivot { get { return m_Pivot; } set { m_Pivot = value; } }
26 public BrushCell[] cells { get { return m_Cells; } }
27 public int cellCount { get { return m_Cells != null ? m_Cells.Length : 0; } }
29 public GameObjectBrush()
31 Init(Vector3Int.one, Vector3Int.zero);
32 SizeUpdated();
35 public void Init(Vector3Int size)
37 Init(size, Vector3Int.zero);
38 SizeUpdated();
41 public void Init(Vector3Int size, Vector3Int pivot)
43 m_Size = size;
44 m_Pivot = pivot;
45 SizeUpdated();
48 public override void Paint(GridLayout gridLayout, GameObject brushTarget, Vector3Int position)
50 // Do not allow editing palettes
51 if (brushTarget.layer == 31)
52 return;
54 Vector3Int min = position - pivot;
55 BoundsInt bounds = new BoundsInt(min, m_Size);
56 BoxFill(gridLayout, brushTarget, bounds);
59 private void PaintCell(GridLayout grid, Vector3Int position, Transform parent, BrushCell cell)
61 if (cell.gameObject != null)
63 SetSceneCell(grid, parent, position, cell.gameObject, cell.offset, cell.scale, cell.orientation);
67 public override void Erase(GridLayout gridLayout, GameObject brushTarget, Vector3Int position)
69 // Do not allow editing palettes
70 if (brushTarget.layer == 31)
71 return;
73 Vector3Int min = position - pivot;
74 BoundsInt bounds = new BoundsInt(min, m_Size);
75 BoxErase(gridLayout, brushTarget, bounds);
78 private void EraseCell(GridLayout grid, Vector3Int position, Transform parent)
80 ClearSceneCell(grid, parent, position);
83 public override void BoxFill(GridLayout gridLayout, GameObject brushTarget, BoundsInt position)
85 // Do not allow editing palettes
86 if (brushTarget.layer == 31)
87 return;
89 if (brushTarget == null)
90 return;
92 foreach (Vector3Int location in position.allPositionsWithin)
94 Vector3Int local = location - position.min;
95 BrushCell cell = m_Cells[GetCellIndexWrapAround(local.x, local.y, local.z)];
96 PaintCell(gridLayout, location, brushTarget.transform, cell);
100 public override void BoxErase(GridLayout gridLayout, GameObject brushTarget, BoundsInt position)
102 // Do not allow editing palettes
103 if (brushTarget.layer == 31)
104 return;
106 if (brushTarget == null)
107 return;
109 foreach (Vector3Int location in position.allPositionsWithin)
111 EraseCell(gridLayout, location, brushTarget.transform);
115 public override void FloodFill(GridLayout gridLayout, GameObject brushTarget, Vector3Int position)
117 Debug.LogWarning("FloodFill not supported");
120 public override void Rotate(RotationDirection direction, Grid.CellLayout layout)
122 Vector3Int oldSize = m_Size;
123 BrushCell[] oldCells = m_Cells.Clone() as BrushCell[];
124 size = new Vector3Int(oldSize.y, oldSize.x, oldSize.z);
125 BoundsInt oldBounds = new BoundsInt(Vector3Int.zero, oldSize);
127 foreach (Vector3Int oldPos in oldBounds.allPositionsWithin)
129 int newX = direction == RotationDirection.Clockwise ? oldSize.y - oldPos.y - 1 : oldPos.y;
130 int newY = direction == RotationDirection.Clockwise ? oldPos.x : oldSize.x - oldPos.x - 1;
131 int toIndex = GetCellIndex(newX, newY, oldPos.z);
132 int fromIndex = GetCellIndex(oldPos.x, oldPos.y, oldPos.z, oldSize.x, oldSize.y, oldSize.z);
133 m_Cells[toIndex] = oldCells[fromIndex];
136 int newPivotX = direction == RotationDirection.Clockwise ? oldSize.y - pivot.y - 1 : pivot.y;
137 int newPivotY = direction == RotationDirection.Clockwise ? pivot.x : oldSize.x - pivot.x - 1;
138 pivot = new Vector3Int(newPivotX, newPivotY, pivot.z);
140 Matrix4x4 rotation = Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(0f, 0f, direction == RotationDirection.Clockwise ? 90f : -90f), Vector3.one);
141 Quaternion orientation = Quaternion.Euler(0f, 0f, direction == RotationDirection.Clockwise ? 90f : -90f);
142 foreach (BrushCell cell in m_Cells)
144 cell.offset = rotation * cell.offset;
145 cell.orientation = cell.orientation * orientation;
149 public override void Flip(FlipAxis flip, Grid.CellLayout layout)
151 if (flip == FlipAxis.X)
152 FlipX();
153 else
154 FlipY();
157 public override void Pick(GridLayout gridLayout, GameObject brushTarget, BoundsInt position, Vector3Int pickStart)
159 // Do not allow editing palettes
160 if (brushTarget.layer == 31)
161 return;
163 Reset();
164 UpdateSizeAndPivot(new Vector3Int(position.size.x, position.size.y, 1), new Vector3Int(pickStart.x, pickStart.y, 0));
166 foreach (Vector3Int pos in position.allPositionsWithin)
168 Vector3Int brushPosition = new Vector3Int(pos.x - position.x, pos.y - position.y, 0);
169 PickCell(pos, brushPosition, gridLayout, brushTarget.transform);
173 private void PickCell(Vector3Int position, Vector3Int brushPosition, GridLayout grid, Transform parent)
175 if (parent != null)
177 Vector3 cellCenter = grid.LocalToWorld(grid.CellToLocalInterpolated(position + new Vector3(.5f, .5f, .5f)));
178 GameObject go = GetObjectInCell(grid, parent, position);
180 if (go != null)
182 Object prefab = PrefabUtility.GetCorrespondingObjectFromSource(go);
184 if (prefab)
186 SetGameObject(brushPosition, (GameObject) prefab);
188 else
190 GameObject newInstance = Instantiate(go);
191 newInstance.hideFlags = HideFlags.HideAndDontSave;
192 SetGameObject(brushPosition, newInstance);
195 SetOffset(brushPosition, go.transform.position - cellCenter);
196 SetScale(brushPosition, go.transform.localScale);
197 SetOrientation(brushPosition, go.transform.localRotation);
202 public override void MoveStart(GridLayout gridLayout, GameObject brushTarget, BoundsInt position)
204 // Do not allow editing palettes
205 if (brushTarget.layer == 31)
206 return;
208 Reset();
209 UpdateSizeAndPivot(new Vector3Int(position.size.x, position.size.y, 1), Vector3Int.zero);
211 if (brushTarget != null)
213 foreach (Vector3Int pos in position.allPositionsWithin)
215 Vector3Int brushPosition = new Vector3Int(pos.x - position.x, pos.y - position.y, 0);
216 PickCell(pos, brushPosition, gridLayout, brushTarget.transform);
217 ClearSceneCell(gridLayout, brushTarget.transform, brushPosition);
222 public override void MoveEnd(GridLayout gridLayout, GameObject brushTarget, BoundsInt position)
224 // Do not allow editing palettes
225 if (brushTarget.layer == 31)
226 return;
228 Paint(gridLayout, brushTarget, position.min);
229 Reset();
232 public void Reset()
234 foreach (var cell in m_Cells)
236 if (cell.gameObject != null && !EditorUtility.IsPersistent(cell.gameObject))
238 DestroyImmediate(cell.gameObject);
241 UpdateSizeAndPivot(Vector3Int.one, Vector3Int.zero);
244 private void FlipX()
246 BrushCell[] oldCells = m_Cells.Clone() as BrushCell[];
247 BoundsInt oldBounds = new BoundsInt(Vector3Int.zero, m_Size);
249 foreach (Vector3Int oldPos in oldBounds.allPositionsWithin)
251 int newX = m_Size.x - oldPos.x - 1;
252 int toIndex = GetCellIndex(newX, oldPos.y, oldPos.z);
253 int fromIndex = GetCellIndex(oldPos);
254 m_Cells[toIndex] = oldCells[fromIndex];
257 int newPivotX = m_Size.x - pivot.x - 1;
258 pivot = new Vector3Int(newPivotX, pivot.y, pivot.z);
259 Matrix4x4 flip = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(-1f, 1f, 1f));
260 Quaternion orientation = Quaternion.Euler(0f, 0f, -180f);
262 foreach (BrushCell cell in m_Cells)
264 Vector3 oldOffset = cell.offset;
265 cell.offset = flip * oldOffset;
266 cell.orientation = cell.orientation*orientation;
270 private void FlipY()
272 BrushCell[] oldCells = m_Cells.Clone() as BrushCell[];
273 BoundsInt oldBounds = new BoundsInt(Vector3Int.zero, m_Size);
275 foreach (Vector3Int oldPos in oldBounds.allPositionsWithin)
277 int newY = m_Size.y - oldPos.y - 1;
278 int toIndex = GetCellIndex(oldPos.x, newY, oldPos.z);
279 int fromIndex = GetCellIndex(oldPos);
280 m_Cells[toIndex] = oldCells[fromIndex];
283 int newPivotY = m_Size.y - pivot.y - 1;
284 pivot = new Vector3Int(pivot.x, newPivotY, pivot.z);
285 Matrix4x4 flip = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(1f, -1f, 1f));
286 Quaternion orientation = Quaternion.Euler(0f, 0f, -180f);
287 foreach (BrushCell cell in m_Cells)
289 Vector3 oldOffset = cell.offset;
290 cell.offset = flip * oldOffset;
291 cell.orientation = cell.orientation * orientation;
295 public void UpdateSizeAndPivot(Vector3Int size, Vector3Int pivot)
297 m_Size = size;
298 m_Pivot = pivot;
299 SizeUpdated();
302 public void SetGameObject(Vector3Int position, GameObject go)
304 if (ValidateCellPosition(position))
305 m_Cells[GetCellIndex(position)].gameObject = go;
308 public void SetOffset(Vector3Int position, Vector3 offset)
310 if (ValidateCellPosition(position))
311 m_Cells[GetCellIndex(position)].offset = offset;
314 public void SetOrientation(Vector3Int position, Quaternion orientation)
316 if (ValidateCellPosition(position))
317 m_Cells[GetCellIndex(position)].orientation = orientation;
320 public void SetScale(Vector3Int position, Vector3 scale)
322 if (ValidateCellPosition(position))
323 m_Cells[GetCellIndex(position)].scale = scale;
326 public int GetCellIndex(Vector3Int brushPosition)
328 return GetCellIndex(brushPosition.x, brushPosition.y, brushPosition.z);
331 public int GetCellIndex(int x, int y, int z)
333 return x + m_Size.x * y + m_Size.x * m_Size.y * z;
336 public int GetCellIndex(int x, int y, int z, int sizex, int sizey, int sizez)
338 return x + sizex * y + sizex * sizey * z;
341 public int GetCellIndexWrapAround(int x, int y, int z)
343 return (x % m_Size.x) + m_Size.x * (y % m_Size.y) + m_Size.x * m_Size.y * (z % m_Size.z);
346 private static GameObject GetObjectInCell(GridLayout grid, Transform parent, Vector3Int position)
348 int childCount = parent.childCount;
349 Vector3 min = grid.LocalToWorld(grid.CellToLocalInterpolated(position));
350 Vector3 max = grid.LocalToWorld(grid.CellToLocalInterpolated(position + Vector3Int.one));
352 // Infinite bounds on Z for 2D convenience
353 min = new Vector3(min.x, min.y, float.MinValue);
354 max = new Vector3(max.x, max.y, float.MaxValue);
356 Bounds bounds = new Bounds((max + min) * .5f, max - min);
358 for (int i = 0; i < childCount; i++)
360 Transform child = parent.GetChild(i);
361 if (bounds.Contains(child.position))
362 return child.gameObject;
364 return null;
367 private bool ValidateCellPosition(Vector3Int position)
369 var valid =
370 position.x >= 0 && position.x < size.x &&
371 position.y >= 0 && position.y < size.y &&
372 position.z >= 0 && position.z < size.z;
373 if (!valid)
374 throw new ArgumentException(string.Format("Position {0} is an invalid cell position. Valid range is between [{1}, {2}).", position, Vector3Int.zero, size));
375 return valid;
378 private void SizeUpdated()
380 m_Cells = new BrushCell[m_Size.x * m_Size.y * m_Size.z];
381 BoundsInt bounds = new BoundsInt(Vector3Int.zero, m_Size);
382 foreach (Vector3Int pos in bounds.allPositionsWithin)
384 m_Cells[GetCellIndex(pos)] = new BrushCell();
388 private static void SetSceneCell(GridLayout grid, Transform parent, Vector3Int position, GameObject go, Vector3 offset, Vector3 scale, Quaternion orientation)
390 if (parent == null || go == null)
391 return;
393 GameObject instance = null;
394 if (PrefabUtility.GetPrefabType(go) == PrefabType.Prefab)
396 instance = (GameObject) PrefabUtility.InstantiatePrefab(go);
398 else
400 instance = Instantiate(go);
401 instance.hideFlags = HideFlags.None;
402 instance.name = go.name;
405 Undo.RegisterCreatedObjectUndo(instance, "Paint GameObject");
406 instance.transform.SetParent(parent);
407 instance.transform.position = grid.LocalToWorld(grid.CellToLocalInterpolated(new Vector3Int(position.x, position.y, position.z) + new Vector3(.5f, .5f, .5f)));
408 instance.transform.localRotation = orientation;
409 instance.transform.localScale = scale;
410 instance.transform.Translate(offset);
413 private static void ClearSceneCell(GridLayout grid, Transform parent, Vector3Int position)
415 if (parent == null)
416 return;
418 GameObject erased = GetObjectInCell(grid, parent, new Vector3Int(position.x, position.y, position.z));
419 if (erased != null)
420 Undo.DestroyObjectImmediate(erased);
423 public override int GetHashCode()
425 int hash = 0;
426 unchecked
428 foreach (var cell in cells)
430 hash = hash * 33 + cell.GetHashCode();
433 return hash;
436 [Serializable]
437 public class BrushCell
439 public GameObject gameObject { get { return m_GameObject; } set { m_GameObject = value; } }
440 public Vector3 offset { get { return m_Offset; } set { m_Offset = value; } }
441 public Vector3 scale { get { return m_Scale; } set { m_Scale = value; } }
442 public Quaternion orientation { get { return m_Orientation; } set { m_Orientation = value; } }
444 [SerializeField]
445 private GameObject m_GameObject;
446 [SerializeField]
447 Vector3 m_Offset = Vector3.zero;
448 [SerializeField]
449 Vector3 m_Scale = Vector3.one;
450 [SerializeField]
451 Quaternion m_Orientation = Quaternion.identity;
453 public override int GetHashCode()
455 int hash = 0;
456 unchecked
458 hash = gameObject != null ? gameObject.GetInstanceID() : 0;
459 hash = hash * 33 + m_Offset.GetHashCode();
460 hash = hash * 33 + m_Scale.GetHashCode();
461 hash = hash * 33 + m_Orientation.GetHashCode();
463 return hash;
468 [CustomEditor(typeof(GameObjectBrush))]
469 public class GameObjectBrushEditor : GridBrushEditorBase
471 public GameObjectBrush brush { get { return target as GameObjectBrush; } }
473 public override void OnPaintSceneGUI(GridLayout gridLayout, GameObject brushTarget, BoundsInt position, GridBrushBase.Tool tool, bool executing)
475 BoundsInt gizmoRect = position;
477 if (tool == GridBrushBase.Tool.Paint || tool == GridBrushBase.Tool.Erase)
478 gizmoRect = new BoundsInt(position.min - brush.pivot, brush.size);
480 base.OnPaintSceneGUI(gridLayout, brushTarget, gizmoRect, tool, executing);
483 public override void OnPaintInspectorGUI()
485 GUILayout.Label("Pick, paint and erase GameObject(s) in the scene.");
486 GUILayout.Label("Limited to children of the currently selected GameObject.");